home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / MNetsrc.hqx / Mac TCP_IP Source v.33 / nr4.c < prev    next >
Text File  |  1989-01-13  |  19KB  |  736 lines

  1. /* net/rom level 4 (transport) protocol implementation
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include "global.h"
  8. #include "mbuf.h"
  9. #include "timer.h"
  10. #include "ax25.h"
  11. #include "lapb.h"
  12. #include "netrom.h"
  13. #include "nr4.h"
  14. #include <ctype.h>
  15.  
  16. #undef NR4DEBUG
  17.  
  18. /* Globals: */
  19.  
  20. /* The circuit table */
  21.  
  22. struct nr4circp Nr4circuits[NR4MAXCIRC] ;
  23.  
  24. /* Various limits */
  25.  
  26. unsigned Nr4window = 4 ;        /* Max window to negotiate */
  27. unsigned Nr4retries = 10 ;        /* Max retries */
  28. unsigned Nr4qlimit = 2048 ;        /* Max bytes on receive queue */
  29.  
  30. /* Timers */
  31.  
  32. long Nr4irtt = 15000 ;            /* Initial round trip time */
  33. long Nr4acktime = 3000 ;        /* ACK delay timer */
  34. long Nr4choketime = 180000 ;    /* CHOKEd state timeout */
  35.  
  36.  
  37. /* This function is called when a net/rom layer four frame */
  38. /* is discovered inside a datagram addressed to us */
  39.  
  40. void
  41. nr4input(hdr,bp)
  42. struct nr4hdr *hdr ;
  43. struct mbuf *bp ;
  44. {
  45.     struct nr4hdr rhdr ;
  46.     struct nr4cb *cb ;
  47.     struct ax25_addr dest ;
  48.     int op ;
  49.     unsigned window ;
  50.     int acceptc ;        /* indicates that connection should be accepted */
  51.     int newconn ;        /* indicates that this is a new incoming */
  52.                         /* connection.  You'll see. */
  53.     int gotchoke ;        /* The choke flag was set in this packet */        
  54.     int i ;
  55.     
  56.     op = hdr->opcode & NR4OPCODE ;    /* Mask off flags */
  57.     
  58.     if (op == NR4OPCONRQ) {            /* process connect request first */
  59.         acceptc = 1 ;
  60.         newconn = 0 ;
  61.  
  62.         /* These fields are sent regardless of success */
  63.         
  64.         rhdr.yourindex = hdr->u.conreq.myindex ;
  65.         rhdr.yourid = hdr->u.conreq.myid ;
  66.         dest = hdr->u.conreq.node ;
  67.  
  68.         /* Check to see if we have already received a connect */
  69.         /* request for this circuit. */
  70.  
  71.         if ((cb = match_n4circ(hdr->u.conreq.myindex, hdr->u.conreq.myid,
  72.                                   &hdr->u.conreq.user, &hdr->u.conreq.node))
  73.              == NULLNR4CB) {    /* No existing circuit if NULL */
  74.  
  75.             /* Try to get a new circuit */
  76.  
  77.             if ((cb = new_n4circ()) == NULLNR4CB) {
  78.                 acceptc = 0 ;
  79.             } else {
  80.             
  81.                 /* Window is set to min of the offered and local windows */
  82.                 
  83.                 window = hdr->u.conreq.window > Nr4window ?
  84.                          Nr4window : hdr->u.conreq.window ;
  85.  
  86.                 if (init_nr4window(cb, window) == -1) {
  87.                     free_n4circ(cb) ;
  88.                     acceptc = 0 ;
  89.                 } else {
  90.                     /* Set up control block */
  91.                     cb->yournum = hdr->u.conreq.myindex ;
  92.                     cb->yourid = hdr->u.conreq.myid ;
  93.                     cb->user = hdr->u.conreq.user ;
  94.                     cb->node = hdr->u.conreq.node ;
  95.                     cb->luser = mycall ;/* we are local user on incomings */
  96.                     cb->srtt = Nr4irtt ;/* Default round trip time */
  97.                     nr4defaults(cb) ;    /* set up timers, window pointers */
  98.                     cb->s_upcall = nr4_incom ;
  99.                     cb->state = NR4STDISC ;
  100.                     newconn = 1 ;
  101.                 } /* End if window successfully allocated */
  102.                 
  103.             }    /* End if new circuit available */
  104.             
  105.          } /* End if no existing circuit matching parameters */
  106.          
  107.         /* Now set up response */
  108.  
  109.         if (!acceptc) {
  110.             rhdr.opcode = NR4OPCONAK | NR4CHOKE ;/* choke means reject */
  111.             rhdr.u.conack.myindex = 0 ;
  112.             rhdr.u.conack.myid = 0 ;
  113.             rhdr.u.conack.window = 0 ;
  114.         } else {
  115.             rhdr.opcode = NR4OPCONAK ;
  116.             rhdr.u.conack.myindex = cb->mynum ;
  117.             rhdr.u.conack.myid = cb->myid ;
  118.             rhdr.u.conack.window = cb->window ;
  119.         }
  120.         nr4sframe(&dest, &rhdr, NULLBUF) ;
  121.  
  122.         /* Why, you ask, do we wait until now for the state change */
  123.         /* upcall?  Well, it's like this:  if the state change triggers */
  124.         /* something like the mailbox to send its banner, the banner */
  125.         /* would have gone out *before* the conn ack if we'd done this */
  126.         /* in the code above.  This is what happens when you don't plan */
  127.         /* too well.  Learn from my mistakes :-) */
  128.         
  129.         if (newconn)
  130.             nr4state(cb, NR4STCON) ;/* connected (no 3-way handshake) */
  131.             
  132.         free_p(bp) ;
  133.         return ;
  134.     } /* end connect request code */
  135.  
  136.     /* validate circuit number */
  137.  
  138.     if ((cb = get_n4circ(hdr->yourindex, hdr->yourid)) == NULLNR4CB) {
  139.         free_p(bp) ;
  140.         return ;
  141.     }
  142.  
  143.     /* Check for choke flag */
  144.  
  145.     if (hdr->opcode & NR4CHOKE)
  146.         gotchoke = 1 ;
  147.     else
  148.         gotchoke = 0 ;
  149.     
  150.     /* Here's where the interesting stuff gets done */
  151.  
  152.     switch (cb->state) {
  153.       case NR4STCPEND:
  154.         switch (op) {
  155.           case NR4OPCONAK:
  156.             stop_timer(&cb->tcd) ;
  157.             if (gotchoke) {                    /* connect rejected */
  158.                 cb->dreason = NR4RREFUSED ;
  159.                 nr4state(cb, NR4STDISC) ;
  160.                 break ;
  161.             }
  162.             cb->yournum = hdr->u.conack.myindex ;
  163.             cb->yourid = hdr->u.conack.myid ;
  164.             window = hdr->u.conack.window > Nr4window ?
  165.                      Nr4window : hdr->u.conack.window ;
  166.  
  167.             if (init_nr4window(cb, window) == -1) {
  168.                 cb->dreason = NR4RRESET ;
  169.                 nr4state(cb, NR4STDISC) ;
  170.             } else {
  171.                 nr4defaults(cb) ;    /* set up timers, window pointers */
  172.                 
  173.                 if (cb->cdtries == 1)             /* No retries */
  174.                     cb->srtt = cb->tcd.count * MSPTICK ;/* Use measured rtt */
  175.                 else
  176.                     cb->srtt = Nr4irtt ;        /* else use default */
  177.                     
  178.                 nr4state(cb, NR4STCON) ;
  179.                 nr4output(cb) ;        /* start sending anything on the txq */
  180.             }
  181.             break ;
  182.  
  183.           default:        /* We can't respond to anything else without */
  184.                           /* Their ID and index */
  185.               free_p(bp) ;
  186.             return ;
  187.         }
  188.         break ;
  189.         
  190.       case NR4STCON:
  191.         switch (op) {
  192.           case NR4OPDISRQ:
  193.             /* format reply packet */
  194.             rhdr.opcode = NR4OPDISAK ;
  195.             rhdr.yourindex = cb->yournum ;
  196.             rhdr.yourid = cb->yourid ;
  197.     
  198.             nr4sframe(&cb->node, &rhdr, NULLBUF) ;
  199.  
  200.             cb->dreason = NR4RREMOTE ;
  201.             nr4state(cb, NR4STDISC) ;
  202.  
  203.             break ;
  204.             
  205.           case NR4OPINFO:
  206.             /* Do receive frame processing */
  207.               nr4rframe(cb, hdr->u.info.txseq, bp) ;
  208.  
  209.             /* Reset the choke flag if no longer choked.  Processing */
  210.             /* the ACK will kick things off again. */
  211.             
  212.             if (cb->choked && !gotchoke) {
  213.                 stop_timer(&cb->tchoke) ;
  214.                 cb->choked = 0 ;
  215.             }
  216.                 
  217.             /* We delay processing the receive sequence number until */
  218.             /* now, because the ACK might pull more off the txq and send */
  219.             /* it, and we want the implied ACK in those frames to be right */
  220.  
  221.             /* Only process NAKs if the choke flag is off.  It appears */
  222.             /* that NAKs should never be sent with choke on, by the way, */
  223.             /* but you never know, considering that there is no official */
  224.             /* standard for this protocol */
  225.             
  226.             if (hdr->opcode & NR4NAK && !gotchoke)
  227.                 nr4gotnak(cb, hdr->u.info.rxseq) ;
  228.  
  229.             /* We always do ACK processing, too, since the NAK of one */
  230.             /* packet may be the implied ACK of another.  The gotchoke */
  231.             /* flag is used to prevent sending any new frames, since */
  232.             /* we are just going to purge them next anyway if this is */
  233.             /* the first time we've seen the choke flag.  If we are */
  234.             /* already choked, this call will return immediately. */
  235.             
  236.             nr4ackours(cb, hdr->u.info.rxseq, gotchoke) ;
  237.  
  238.             /* If we haven't seen the choke flag before, purge the */
  239.             /* send window and set the timer and the flag. */
  240.             
  241.             if (!cb->choked && gotchoke)
  242.                 nr4choke(cb) ;
  243.             
  244.             break ;
  245.  
  246.           case NR4OPACK:
  247.             if (cb->choked && !gotchoke) {    /* clear choke if appropriate */
  248.                 stop_timer(&cb->tchoke) ;
  249.                 cb->choked = 0 ;
  250.             }
  251.                 
  252.               if (hdr->opcode & NR4NAK && !gotchoke)
  253.                 nr4gotnak(cb, hdr->u.ack.rxseq) ;    /* process NAKs */
  254.                 
  255.               nr4ackours(cb, hdr->u.ack.rxseq, gotchoke) ; /* and ACKs */
  256.  
  257.             if (!cb->choked && gotchoke)    /* First choke seen */
  258.                 nr4choke(cb) ;                /* Set choke status */
  259.  
  260.             break ;
  261.         }
  262.         break ;
  263.         
  264.       case NR4STDPEND:
  265.         switch (op) {
  266.           case NR4OPDISAK:
  267.               cb->dreason = NR4RNORMAL ;
  268.             nr4state(cb, NR4STDISC) ;
  269.             break ;
  270.             
  271.           case NR4OPINFO:
  272.             /* We can still do receive frame processing until */
  273.             /* the disconnect acknowledge arrives, but we won't */
  274.             /* bother to process ACKs, since we've flushed our */
  275.             /* transmit buffers and queue already. */
  276.             
  277.               nr4rframe(cb, hdr->u.info.txseq, bp) ;
  278.  
  279.             break ;
  280.         }
  281.     
  282.     }    /* End switch(state) */
  283.  
  284. }
  285.  
  286.  
  287. /* Send a net/rom layer 4 frame.  bp should be NULLBUF unless the frame
  288.  * type is info.
  289.  */
  290.  
  291. void
  292. nr4sframe(dest, hdr, bp)
  293. struct ax25_addr *dest ;
  294. struct nr4hdr *hdr ;
  295. struct mbuf *bp ;
  296. {
  297.     struct mbuf *n4b ;
  298.  
  299.     if ((n4b = htonnr4(hdr)) == NULLBUF) {
  300.         free_p(bp) ;
  301.         return ;
  302.     } else {
  303.         append(&n4b, bp) ;
  304.         nr3output(dest, n4b) ;
  305.     }
  306. }
  307.  
  308. /* Receive frame processing */
  309.  
  310. void
  311. nr4rframe(cb, rxseq, bp)
  312. struct nr4cb *cb ;
  313. unsigned rxseq ;
  314. struct mbuf *bp ;
  315. {
  316.     struct nr4hdr rhdr ;
  317.     unsigned window = cb->window ;
  318.     unsigned rxbuf = rxseq % window ;
  319.     unsigned newdata = 0 ;        /* whether to upcall */
  320.  
  321. #ifdef NR4DEBUG
  322.     printf("Processing received info\n") ;
  323. #endif
  324.  
  325.     /* If we're choked, just reset the ACK timer to blast out */
  326.     /* another CHOKE indication after the ackdelay */
  327.  
  328.     if (cb->qfull) {
  329.         start_timer(&cb->tack) ;
  330.         return ;
  331.     }
  332.     
  333.     /* If the frame is out of sequence, NAK it if we haven't */
  334.     /* already done so */
  335.     
  336.       if (rxseq != cb->rxpected && !cb->naksent) {
  337. #ifdef NR4DEBUG
  338.         printf("Frame out of sequence -- expected %u, got %u.\n",
  339.                cb->rxpected, rxseq) ;
  340. #endif                
  341.         rhdr.opcode = NR4OPACK | NR4NAK ;
  342.         rhdr.yourindex = cb->yournum ;
  343.         rhdr.yourid = cb->yourid ;
  344.         rhdr.u.ack.rxseq = cb->rxpected ;
  345.         nr4sframe(&cb->node, &rhdr, NULLBUF) ;
  346.         
  347.         /* Now make sure we don't send any more of these until */
  348.         /* we see some good data.  Otherwise full window retransmissions */
  349.         /* would result in a flurry of NAKs */
  350.         
  351.         cb->naksent = 1 ;
  352.     }
  353.             
  354.     /* If this is a new frame, within the window, buffer it, */
  355.     /* then see what we can deliver */
  356.             
  357.     if (nr4between(cb->rxpected,rxseq,cb->rxpastwin)
  358.         && !cb->rxbufs[rxbuf].occupied) {
  359. #ifdef NR4DEBUG
  360.         printf("Frame within window\n") ;
  361. #endif
  362.         cb->rxbufs[rxbuf].occupied = 1 ;
  363.         cb->rxbufs[rxbuf].data = bp ;
  364.                 
  365.         for (rxbuf = cb->rxpected % window ; cb->rxbufs[rxbuf].occupied ; 
  366.              rxbuf = cb->rxpected % window) {
  367. #ifdef NR4DEBUG
  368.             printf("Removing frame from buffer %d\n", rxbuf) ;
  369. #endif
  370.             newdata = 1 ;
  371.             cb->rxbufs[rxbuf].occupied = 0 ;
  372.             append(&cb->rxq,cb->rxbufs[rxbuf].data) ;
  373.             cb->rxbufs[rxbuf].data = NULLBUF ;
  374.             cb->rxpected = (cb->rxpected + 1) & NR4SEQMASK ;
  375.             cb->rxpastwin = (cb->rxpastwin + 1) & NR4SEQMASK ;
  376.         }
  377.         if (newdata) {
  378.             cb->naksent = 0 ;    /* OK to send NAKs again */
  379.             if (cb->r_upcall != NULLVFP)
  380.                 (*cb->r_upcall)(cb,len_mbuf(cb->rxq)) ;
  381.  
  382.             /* Now that our upcall has had a shot at the queue, */
  383.             /* see if it's past the queue length limit.  If so, */
  384.             /* go into choked mode (i.e. flow controlled). */
  385.  
  386.             if (len_mbuf(cb->rxq) > Nr4qlimit) {
  387.                 cb->qfull = 1 ;
  388.                 nr4ackit((char *)cb) ;    /* Tell `em right away */
  389.             } else
  390.                 start_timer(&cb->tack) ;
  391.         }
  392.     } else     /* It's out of the window or we've seen it already */
  393.         free_p(bp) ;
  394. }
  395.  
  396.  
  397. /* Send the transmit buffer whose sequence number is seq */
  398.  
  399. void
  400. nr4sbuf(cb, seq)
  401. struct nr4cb *cb ;
  402. unsigned seq ;
  403. {
  404.     struct nr4hdr hdr ;
  405.     struct mbuf *bufbp, *bp ;
  406.     unsigned bufnum = seq % cb->window ;
  407.     struct timer *t ;
  408.     
  409.     /* sanity check */
  410.  
  411.     if (bufnum >= cb->window) {
  412. #ifdef NRDEBUG
  413.         printf("sbuf: buffer number %u beyond window\n",bufnum) ;
  414. #endif
  415.         return ;
  416.     }
  417.  
  418.     /* Stop the ACK timer, since our sending of the frame is */
  419.     /* an implied ACK. */
  420.  
  421.     stop_timer(&cb->tack) ;
  422.     
  423.     /* Duplicate the mbuf, since we have to keep it around */
  424.     /* until it is acknowledged */
  425.     
  426.     bufbp = cb->txbufs[bufnum].data ;
  427.  
  428.     /* Notice that we use copy_p instead of dup_p.  This is because */
  429.     /* a frame can still be sitting on the AX.25 send queue when it */
  430.     /* get acknowledged, and we don't want to deallocate its data */
  431.     /* before it gets sent! */
  432.     
  433.     if ((bp = copy_p(bufbp, len_mbuf(bufbp))) == NULLBUF) {
  434.         free_mbuf(bp) ;
  435.         return ;
  436.     }
  437.  
  438.     /* Prepare the header */
  439.     if (cb->qfull)                /* are we choked? */
  440.         hdr.opcode = NR4OPINFO | NR4CHOKE ;
  441.     else
  442.         hdr.opcode = NR4OPINFO ;
  443.     hdr.yourindex = cb->yournum ;
  444.     hdr.yourid = cb->yourid ;
  445.     hdr.u.info.txseq = (unsigned char)(seq & NR4SEQMASK) ;
  446.     hdr.u.info.rxseq = cb->rxpected ;
  447.     
  448.     /* Send the frame, then set and start the timer */
  449.  
  450.     nr4sframe(&cb->node, &hdr, bp) ;
  451.  
  452.     t = &cb->txbufs[bufnum].tretry ;
  453.     t->start = (1 << cb->blevel) *
  454.                (2 * cb->mdev + cb->srtt + MSPTICK) / MSPTICK ;
  455.     start_timer(t) ;
  456.  
  457.     return ;
  458. }
  459.  
  460. /* Check to see if any of our frames have been ACKed */
  461.  
  462. void
  463. nr4ackours(cb, seq, gotchoke)
  464. struct nr4cb *cb ;
  465. unsigned seq ;
  466. int gotchoke ;    /* The choke flag is set in the received frame */
  467. {
  468.     unsigned txbuf ;
  469.     struct timer *t ;
  470.     
  471.     /* If we are choked, there is nothing in the send window */
  472.     /* by definition, so we can just return. */
  473.     
  474.     if (cb->choked)
  475.         return ;
  476.         
  477.     /* Adjust seq to point to the frame being ACK'd, not the one */
  478.     /* beyond it, which is how it arrives. */
  479.  
  480.     seq = (seq - 1) & NR4SEQMASK ;
  481.  
  482.     /* Free up all the ack'd frames, and adjust the round trip */
  483.     /* timing stuff */
  484.     
  485.     while (nr4between(cb->ackxpected, seq, cb->nextosend)) {
  486. #ifdef NR4DEBUG
  487.         printf("Sequence # %u acknowledged\n", seq) ;
  488. #endif
  489.         cb->nbuffered-- ;
  490.         txbuf = cb->ackxpected % cb->window ;
  491.         stop_timer(&cb->txbufs[txbuf].tretry) ;
  492.         free_mbuf(cb->txbufs[txbuf].data) ;
  493.         cb->txbufs[txbuf].data = NULLBUF ;
  494.         cb->ackxpected = (cb->ackxpected + 1) & NR4SEQMASK ;
  495.  
  496.         /* Round trip time estimation, cribbed from TCP */
  497.  
  498.         if (cb->txbufs[txbuf].retries == 0) {    /* We only sent this one once */
  499.             int32 rtt ;
  500.             int32 abserr ;
  501.  
  502.             t = &cb->txbufs[txbuf].tretry ;
  503.             rtt = (t->start - t->count) * MSPTICK ;    /* get our rtt in msec */
  504.             abserr = (rtt > cb->srtt) ? rtt - cb->srtt : cb->srtt - rtt ;
  505.             cb->srtt = (cb->srtt * 7 + rtt) >> 3 ;
  506.             cb->mdev = (cb->mdev * 3 + abserr) >> 2 ;
  507.  
  508.             /* Reset the backoff level */
  509.  
  510.             cb->blevel = 0 ;
  511.         } 
  512.     }
  513.  
  514.     /* Now we recalculate tmax, the maximum number of retries for */
  515.     /* any frame in the window.  tmax is used as a baseline to */
  516.     /* determine when the window has reached a new high in retries. */
  517.     /* We don't want to increment blevel for every frame that times */
  518.     /* out, since that would lead to us backing off too fast when */
  519.     /* all the frame timers expired at around the same time. */
  520.  
  521.     cb->txmax = 0 ;
  522.     
  523.     for (seq = cb->ackxpected ;
  524.          nr4between(cb->ackxpected, seq, cb->nextosend) ;
  525.          seq = (seq + 1) & NR4SEQMASK)
  526.         if (cb->txbufs[seq % cb->window].retries > cb->txmax)
  527.             cb->txmax = cb->txbufs[seq % cb->window].retries ;
  528.  
  529.     /* This is kind of a hack.  This function is called under */
  530.     /* three different conditions:  either we are choked, in */
  531.     /* which case we return immediately, or we are not choked, */
  532.     /* in which case we proceed normally to keep the send */
  533.     /* window full, or we have seen the choke flag for the first */
  534.     /* time.  In the last case, gotchoke is true while cb->choked */
  535.     /* is false.  We want to process any acknowledgments of existing */
  536.     /* frames in the send window before we purge it, while at the */
  537.     /* same time we don't want to take anything else off the txq */
  538.     /* or send it out.  So, in the third case we listed, we return */
  539.     /* now since we've processed the ACK. */
  540.     
  541.     if (gotchoke)
  542.         return ;
  543.         
  544.     nr4output(cb) ;            /* yank stuff off txq and send it */
  545.  
  546.     /* At this point, either the send window is full, or */
  547.     /* nr4output() didn't find enough on the txq to fill it. */
  548.     /* If the window is not full, then the txq must be empty, */
  549.     /* and we'll make a tx upcall */
  550.     
  551.     if (cb->nbuffered < cb->window)    
  552.         if (cb->t_upcall != NULLVFP)
  553.             (*cb->t_upcall)(cb, (cb->window - cb->nbuffered) * NR4MAXINFO) ;
  554.  
  555. }
  556.  
  557.  
  558. /* If the send window is open and there are frames on the txq,
  559.  * move as many as possible to the transmit buffers and send them.
  560.  * Return the number of frames sent.
  561.  */
  562.  
  563. int
  564. nr4output(cb)
  565. struct nr4cb *cb ;
  566. {
  567.     int numq, i ;
  568.     struct mbuf *bp ;
  569.     struct nr4txbuf *tp ;
  570.  
  571.     /* Are we in the proper state? */
  572.  
  573.     if (cb->state != NR4STCON || cb->choked)
  574.         return 0 ;                /* No sending if not connected */
  575.                                 /* or if choked */
  576.         
  577.     /* See if the window is open */
  578.     
  579.     if (cb->nbuffered >= cb->window)
  580.         return 0 ;
  581.  
  582.     numq = len_q(cb->txq) ;
  583.     
  584. #ifdef NR4DEBUG
  585.     printf("nr4output: %d packets on txq\n", numq) ;
  586. #endif
  587.     
  588.     for (i = 0 ; i < numq ; i++) {
  589.  
  590.         bp = dequeue(&cb->txq) ;
  591.  
  592. #ifdef NR4DEBUG
  593.         if (len_mbuf(bp) > NR4MAXINFO) {    /* should be checked higher up */
  594.             printf("Upper layers queued too big a buffer\n") ;
  595.             continue ;
  596.         }
  597. #endif
  598.         /* Set up and send buffer */
  599.         
  600.         tp = &cb->txbufs[cb->nextosend % cb->window] ;
  601.         tp->retries = 0 ;
  602.         tp->data = bp ;
  603.         nr4sbuf(cb, cb->nextosend) ;
  604.  
  605.         /* Update window and buffered count */
  606.  
  607.         cb->nextosend = (cb->nextosend + 1) & NR4SEQMASK ;
  608.         if (++cb->nbuffered >= cb->window)
  609.             break ;
  610.     }
  611.     return i ;        
  612. }
  613.  
  614. void
  615. nr4state(cb, newstate)
  616. struct nr4cb *cb ;
  617. int newstate ;
  618. {
  619.     int i ;
  620.     int oldstate = cb->state ;
  621.     
  622.     cb->state = newstate ;
  623.  
  624.     switch (cb->state) {
  625.       case NR4STDPEND:
  626.           stop_timer(&cb->tchoke);
  627.  
  628.         /* When we request a disconnect, we lose the contents of */
  629.         /* our transmit queue and buffers, but we retain our ability */
  630.         /* to receive any packets in transit until a disconnect */
  631.         /* acknowledge arrives */
  632.         
  633.         free_q(&cb->txq) ;
  634.         
  635.         for (i = 0 ; i < cb->window ; i++) {
  636.             free_mbuf(cb->txbufs[i].data) ;
  637.             cb->txbufs[i].data = NULLBUF ;
  638.             stop_timer(&cb->txbufs[i].tretry) ;
  639.         }
  640.             
  641.         break ;
  642.         
  643.       case NR4STDISC:
  644.         stop_timer(&cb->tchoke) ;
  645.         stop_timer(&cb->tack) ;
  646.         stop_timer(&cb->tcd) ;
  647.  
  648.         /* We don't clear the rxq, since the state change upcall */
  649.         /* may pull something off of it at the last minute. */
  650.         
  651.         free_q(&cb->txq) ;
  652.  
  653.         /* The following loop will only be executed if the */
  654.         /* window was set, since when the control block is */
  655.         /* calloc'd the window field gets a 0 in it.  This */
  656.         /* protects us from dereferencing an unallocated */
  657.         /* window buffer pointer */
  658.         
  659.         for (i = 0 ; i < cb->window ; i++) {
  660.             free_mbuf(cb->rxbufs[i].data) ;
  661.             cb->rxbufs[i].data = NULLBUF ;
  662.             free_mbuf(cb->txbufs[i].data) ;
  663.             cb->txbufs[i].data = NULLBUF ;
  664.             stop_timer(&cb->txbufs[i].tretry) ;
  665.         }
  666.             
  667.         break ;
  668.     }
  669.  
  670.     if (oldstate != newstate && cb->s_upcall != NULLVFP)
  671.         (*cb->s_upcall)(cb, oldstate, newstate) ;
  672.  
  673.     /* We take responsibility for deleting the circuit */
  674.     /* descriptor.  Don't do this anywhere else! */
  675.     
  676.     if (newstate == NR4STDISC)
  677.         free_n4circ(cb) ;
  678.     
  679. }
  680.  
  681. /* Process NAKs.  seq indicates the next frame expected by the
  682.  * NAK'ing station.
  683.  */
  684.  
  685. void
  686. nr4gotnak(cb, seq)
  687. struct nr4cb *cb ;
  688. unsigned seq ;
  689. {
  690.     if (nr4between(cb->ackxpected, seq, cb->nextosend))
  691.         nr4sbuf(cb, seq) ;
  692. }
  693.  
  694.  
  695. /* This is called when we first get a CHOKE indication from the
  696.  * remote.  It purges the send window and sets the choke timer.
  697.  */
  698.  
  699. void
  700. nr4choke(cb)
  701. struct nr4cb *cb ;
  702. {
  703.     int i ;
  704.     unsigned seq ;
  705.     struct mbuf *q, *bp ;
  706.     struct nr4txbuf *t ;
  707.  
  708.     q = cb->txq ;
  709.  
  710.     /* We purge the send window, returning the buffers to the */
  711.     /* txq in the proper order. */
  712.  
  713.     for (seq = (cb->nextosend - 1) & NR4SEQMASK ;
  714.          nr4between(cb->ackxpected, seq, cb->nextosend) ;
  715.          seq = (seq - 1) & NR4SEQMASK) {
  716.  
  717.         t = &cb->txbufs[seq % cb->window] ;
  718.         stop_timer(&t->tretry) ;
  719.         bp = t->data ;
  720.         t->data = NULLBUF ;
  721.         enqueue(&bp, q) ;    /* prepend this packet to the queue */
  722.         q = bp ;
  723.      }
  724.  
  725.     cb->nextosend = cb->ackxpected ;    /* close the window */
  726.     cb->nbuffered = 0 ;                    /* nothing in the window */
  727.     cb->txq = q ;            /* Replace the txq with the one that has */
  728.                             /* the purged packets prepended */
  729.     cb->choked = 1 ;        /* Set the choked flag */
  730.  
  731.     start_timer(&cb->tchoke) ;
  732.     
  733. }
  734.  
  735.  
  736.